<?php
// класс парсера HTML 
class Parser {
	private $_DOM = NULL, $_XPATH = NULL;
	public // конструктор // конструктор
	function __construct($html = "") {
		$this->LoadFromHTML ( $html );
	}
	// загрузка из HTML
	function LoadFromHTML($html) {
		// проверка на пустоту
		if (strlen ( $html ) == 0) {
			return FALSE;
		}
		// создание нового DOM документа
		$tDOM = new DOMDocument ( "1.0", "UTF-8" );
		$tDOM->preserveWhiteSpace = FALSE;
		libxml_use_internal_errors ( TRUE );
		// загрузка
		$bLoad = $tDOM->loadHTML ( $html );
		libxml_clear_errors ();
		// проверка удачной загрузки документа
		if ($bLoad) {
			$this->SetDom ( $tDOM );
		}
		return $bLoad;
	}
	// выбор элемента
	function GET($select) {
		// если есть несколько условий
		if (strpos ( $select, ' ' )) {
			// разбивка условий поиска
			$tArr = explode ( ' ', $select );
			$select = "";
			foreach ( $tArr as $s ) {
				$select .= $this->GetXQuery ( $s );
			}
			return $this->GetElements ( $select );
		}
		return $this->GetElements ( $this->GetXQuery ( $select ) );
	}
	function toArr($sep = '', $sNode = NULL) {
		$retArr = array ();
		if (! $sNode) {
			$sNode = $this->_DOM->firstChild;
		}
		// атрибуты
		if ($sNode->hasAttributes ()) {
			foreach ( $sNode->attributes as $attr ) {
				$retArr [$attr->nodeName] = $attr->nodeValue;
			}
		}
		// текст
		//if ($sNode->nodeValue) {$retArr["text"]   = trim(utf8_decode($sNode->nodeValue)).$sep;}
		if ($sNode->nodeValue) {
			$retArr ["text"] = trim ( $sNode->nodeValue ) . $sep;
		}
		// tag
		if ($sNode->nodeName) {
			$retArr ["tag"] = $sNode->nodeName;
		}
		// дочерние элементы
		if ($sNode->hasChildNodes ()) {
			$i = 0;
			foreach ( $sNode->childNodes as $childNode ) {
				if ($childNode->nodeType != XML_TEXT_NODE) {
					$retArr ["childs"] [] = $this->toArr ( $sep, $childNode );
					$i ++;
				}
			}
			$retArr ["childs"] ["length"] = $i;
			if ($i == 1 && $retArr ["tag"] == "root") {
				$retArr = $retArr ["childs"] [0];
			}
		}
		return $retArr;
	}
	function toXML() {
		return $this->_DOM->saveXML ();
	}
	protected // формирование запроса выборки // формирование запроса выборки
	function GetXQuery($select) {
		$retQuery = "";
		if (preg_match ( "/(?P<tag>[a-z0-9]+)?(\[(?P<attr>\S+)=(?P<value>\S+)\])?(#(?P<id>\S+))?(\.(?P<class>\S+))?/ims", $select, $match )) {
			$selArr = array ("tag" => $match ["tag"], "id" => $match ["id"], "attr" => $match ["attr"], "value" => $match ["value"], "class" => $match ["class"] );
			// tag
			if (! strlen ( $match ["tag"] )) {
				$match ["tag"] = "*";
			}
			$retQuery = "//" . $match ["tag"];
			// #id
			if (strlen ( $match ["id"] )) {
				$retQuery .= "[@id='" . $match ["id"] . "']";
			}
			// atribute
			if (strlen ( $match ["attr"] )) {
				$retQuery .= "[@" . $match ["attr"] . "='" . $match ["value"] . "']";
			}
			// .class
			if (strlen ( $match ["class"] )) {
				$retQuery .= '[contains(concat(" ", normalize-space(@class), " "), " ' . $match ["class"] . ' ")]';
			}
		}
		return $retQuery;
	}
	// выбор элементов из документа
	function GetElements($select) {
		if (! strlen ( $select )) {
			return FALSE;
		}
		$tDOM = new DOMDocument ( "1.0", "UTF-8" );
		$nodeRoot = $tDOM->createElement ( "root" );
		$tDOM->appendChild ( $nodeRoot );
		$nodesList = $this->_XPATH->query ( $select );
		if ($nodesList === false) {
			return FALSE;
		}
		foreach ( $nodesList as $node ) {
			$iNode = $tDOM->importNode ( $node, true );
			$nodeRoot->appendChild ( $iNode );
		}
		return self::GetDOM ( $tDOM );
	}
	// утсановка DOM
	function SetDom($setDOM) {
		$this->_DOM = $setDOM;
		$this->_XPATH = new DOMXPath ( $this->_DOM );
	}
	// создание экземпляра класса с полученными элементами
	function GetDOM($setDOM) {
		$nParser = new Parser ();
		$nParser->SetDom ( $setDOM );
		return $nParser;
	}
}
?>